package com.yx.changdao.web.config.shiro.realm;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yx.changdao.common.entity.SysPermission;
import com.yx.changdao.common.entity.SysRole;
import com.yx.changdao.common.entity.SysUser;
import com.yx.changdao.common.utils.MD5Utils;
import com.yx.changdao.common.utils.SysConst;
import com.yx.changdao.service.SysRolePermissionService;
import com.yx.changdao.service.SysUserRoleService;
import com.yx.changdao.service.SysUserService;
import com.yx.changdao.web.config.shiro.token.LoginToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 自定义realm
 * <p>
 * 系统登录realm
 *
 * @author wangzd
 * @createtime 2019-11-04 13:17
 */
public class SysLoginRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(SysLoginRealm.class);

    // 系统用户
    @Autowired
    private SysUserService sysUserService;

    // 角色权限
    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    // 用户角色
    @Autowired
    private SysUserRoleService sysUserRoleService;

    public SysLoginRealm() {
//        this.setCredentialsMatcher(new HashedCredentialsMatcher(Sha256Hash.ALGORITHM_NAME));
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

//    /**
//     * 设置该Realm的名字
//     *
//     * @param name
//     */
//    public void setName(String name) {
//        super.setName("sysLoginRealm");
//    }

    /**
     * 授权信息，执行授权逻辑
     * <p>
     * 角色/权限
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        if (principals == null) {
            logger.error("doGetAuthorizationInfo.方法参数不能为null !");
            throw new AuthorizationException("身份验证异常!");
        }

        // 获取安全数据
        SysUser sysUser = (SysUser) principals.getPrimaryPrincipal();

        if (sysUser == null) {
            return null;
        }

        SimpleAuthorizationInfo auth = new SimpleAuthorizationInfo();

        List<SysRole> roles = null;
        roles = this.sysUserRoleService.getUserRoles(sysUser.getUserId());

        if (roles != null) {
            for (SysRole role : roles) {
                auth.addRole(role.getRoleId());
                List<SysPermission> permissions = new ArrayList<SysPermission>();
                // 判断如果用户是管理员则默认开启所有权限
                if (SysConst.SYS_ROLE.equals(role.getRoleId())) {
                    permissions = this.sysRolePermissionService.getAllPermissions();
                } else {
                    // 获取该角色的权限
                    permissions = this.sysRolePermissionService.getRolePermissions(role.getRoleId());
                }
                for (SysPermission permission : permissions) {
                    auth.addStringPermission(permission.getPermId());
                }
            }
        }
        return auth;
    }

    /**
     * 身份验证信息，执行认证逻辑
     * <p>
     * 账户/密码/验证码。。。
     *
     * @param authcToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        LoginToken loginToken = (LoginToken) authcToken;

        String username = loginToken.getUsername();
        String pwd = new String(loginToken.getPassword());

        // 根据用户名查询
        SysUser sysUser = this.sysUserService.getOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUsername, username));

        // 判断用户是否存在
        if (Objects.isNull(sysUser)) {
            throw new UnknownAccountException("用户不存在");
        }

        // 获取盐
        String salt = sysUser.getSalt();

        // 获取密密码
        String password = sysUser.getPassword();

        // 用户输入的密码加密
        String encodedPassword = MD5Utils.shiroEncryption(pwd, salt);

        // 判断密码
        if (!StringUtils.equals(password, encodedPassword)) {
            throw new AccountException("账号或密码不正确");
        }


        // 返回安全数据
        return new SimpleAuthenticationInfo(sysUser, pwd, ByteSource.Util.bytes(salt), this.getName());
    }


}
